#include <iostream>
#include "OperationMode_OFB.hpp"

OperationMode_OFB::OperationMode_OFB(Algorithm &system, unsigned int j) : OperationMode(system) {
	R = Block(system.getBlockSize(), 0xff);
	this->j = j;
}

OperationMode_OFB::OperationMode_OFB(Algorithm &system, Block& iv, unsigned char j) : OperationMode(system) {
	R = iv;
	this->j = j;
}

Block OperationMode_OFB::encrypt(const Block &plaintext) {
	
	//encrypt register
	Block encrypted = system.encrypt(R);
	//extract first j bits
	Block firstPart = Block(encrypted.get(), j / 8);
	
	//XOR with Plaintext
	Block ciphertext = plaintext;
	ciphertext ^= firstPart;
	
	//shift register
	R <<= j;
	//and append the firstPart
	unsigned char* array = R.get();
	memcpy(array + 16 -(j / 8), firstPart.get(), j / 8);
	//finally store the result in the register again
	R = Block(array, 16);
	
	return ciphertext;
}

Block OperationMode_OFB::decrypt(const Block &ciphertext) {
	
	//encrypt register
	Block decrypted = system.encrypt(R);
	//extract first j bits
	Block firstPart = Block(decrypted.get(), j / 8);
	
	//XOR with Plaintext
	Block plaintext = ciphertext;
	plaintext ^= firstPart;
	
	//shift register
	R <<= j;
	//and append the firstPart
	unsigned char* array = R.get();
	memcpy(array + 16 -(j / 8), firstPart.get(), j / 8);
	//finally store the result in the register again
	R = Block(array, 16);
	
	return plaintext;
}
